package utils

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"log"
	"math"
	"math/rand"
	"reflect"
	"strconv"
	"time"

	"gopkg.in/mgo.v2/bson"
)

func PtrOfInt(i int) *int {
	return &i
}

func PtrOfString(i string) *string {
	return &i
}

func PtrOfInt64(i int64) *int64 {
	return &i
}

func PtrOfFloat64(i float64) *float64 {
	return &i
}

func OnErrorResume() (err error) {

	r := recover()

	if r != nil {
		switch r.(type) {
		case error:
			err = r.(error)
		case string:
			err = errors.New(r.(string))
		default:
			err = errors.New("unknown panic!")
			log.Println(err)
		}
	}

	return
}

// //截取字符串 start 起点下标 length 需要截取的长度
func Substr(str string, start int, length int) string {
	rs := []rune(str)
	rl := len(rs)
	end := 0

	if start < 0 {
		start = rl - 1 + start
	}
	end = start + length

	if start > end {
		start, end = end, start
	}

	if start < 0 {
		start = 0
	}
	if start > rl {
		start = rl
	}
	if end < 0 {
		end = 0
	}
	if end > rl {
		end = rl
	}

	return string(rs[start:end])
}

func MustJSONString(g interface{}) string {
	s, _ := JSONString(g)
	return s
}

func JSONString(g interface{}) (string, error) {

	bs, err := json.Marshal(g)

	if err != nil {
		return "", err
	}

	return string(bs), err
}

func ParseJSON(s string, v interface{}) error {

	return json.Unmarshal([]byte(s), v)
}

func RandInt(min, max int) int {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	s := r.Intn(max - min)
	return min + s
}

func Round(f float64, n int) float64 {
	pow10_n := math.Pow10(n)
	return math.Trunc((f+0.5/pow10_n)*pow10_n) / pow10_n
}

func Guid() string {
	return bson.NewObjectId().Hex()
}

func Index(vs []string, t string) int {
	for i, v := range vs {
		if v == t {
			return i
		}
	}
	return -1
}

func Include(vs []string, t string) bool {
	return Index(vs, t) >= 0
}

func IsEmpty(a interface{}) bool {
	v := reflect.ValueOf(a)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	return v.Interface() == reflect.Zero(v.Type()).Interface()
}

func StringToInt(s string) int {
	i, _ := strconv.Atoi(s)
	return i
}

func StringToInt64(s string) int64 {
	i64, _ := strconv.ParseInt(s, 10, 64)
	return i64
}

func IntToString(i int) string {
	s := strconv.Itoa(i)
	return s
}

func Int64ToString(i int64) string {
	s := strconv.FormatInt(i, 10)
	return s
}

func StringToFloat64(s string) float64 {
	f, _ := strconv.ParseFloat(s, 64)
	return f
}

func Float64ToString(f float64) string {
	s := strconv.FormatFloat(f, 'E', -1, 64)
	return s
}

func getRandomString(tp int) func(int) string {
	bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	if tp == 1 {
		bytes = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%&*_+")
	}

	return func(length int) string {

		result := make([]byte, length)

		for i := 0; i < length; i++ {
			result[i] = bytes[rand.Intn(len(bytes))]
		}

		return string(result)
	}
}

var randString = getRandomString(0)

//随机字符串
func GetRandomString(length int) string {
	return randString(length)
}

//随机字符串(包括特殊字符)
func GetRandomCharacter(length int) string {
	return getRandomString(1)(length)
}

/**
@note:标准的字符串加密
@param src:目标字符串
@param salt:盐值
*/
func Encrypt(src string, salt string) string {

	hash := sha256.New()

	hash.Write([]byte(src))
	hash.Write([]byte("$"))
	hash.Write([]byte(salt))

	return hex.EncodeToString(hash.Sum(nil))
}
